import { WebGLRenderer, MeshBasicMaterial, PointsMaterial, BoxGeometry, Points, Mesh, SphereGeometry, Vector2, Raycaster, MeshPhysicalMaterial, AnimationMixer, Camera, Scene, PerspectiveCamera, AxesHelper } from 'three'
import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment';
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js' //模型加载器
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' //鼠标控制器
import useLogin from '../useLogin/useLogin';
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
// eslint-disable-next-line react-hooks/rules-of-hooks
const [show, hide] = useLogin()
// three常用的一些配置都在这里设置好了---
export default class useThree {
  mouseControls: OrbitControls //轨道控制
  camera: Camera //相机
  renderers: WebGLRenderer = new WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true }) //渲染器
  scene: Scene = new Scene() // 创建3D场景对象Scene
  dom: HTMLDivElement //放three的盒子
  width: number //模型的宽
  dirLight = new THREE.DirectionalLight(0xffffff, .5)
  height: number //模型的高
  constructor(uuid: string) {
    this.dom = document.getElementById(uuid) as HTMLDivElement
    this.width = this.dom.clientWidth
    this.height = this.dom.clientHeight
    this.init()
  }
  // 初始化
  init() {
    this.getPerspectiveCamera()//相机
    this.getrenderder()//渲染器
    this.getAmbientLight()//灯光
    this.getDirectionalLight()//平行光
    this.getHemisphereLight()//半球光源
    this.createOrbitControls() //创建轨道控制
    this.renderScene() //动画
    this.getPlaneGeometry()//创建地面
    this.getother()//其他选项

  }
  // 灯光
  getAmbientLight() {
    const ambientLight = new THREE.AmbientLight("white");
    this.scene.add(ambientLight);
  }
  // 半球光源
  getHemisphereLight() {
    const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, .1);
    hemiLight.position.set(0, 200, 0);
    // this.scene.add(hemiLight);
  }
  // 平行光
  getDirectionalLight() {
    this.dirLight.position.set(0, 300, 100);
    this.dirLight.castShadow = true;
    this.dirLight.shadow.camera.top = 500;
    this.dirLight.shadow.camera.bottom = - 1000;
    this.dirLight.shadow.camera.left = - 1200;
    this.dirLight.shadow.camera.right = 1200;
    this.dirLight.shadow.mapSize.width = 2048  // default
    this.dirLight.shadow.mapSize.height = 2048  // default
    this.dirLight.shadow.camera.near = 0.05  // default
    this.dirLight.shadow.camera.far = 500  // default

    this.scene.add(this.dirLight);
  }
  // 相机
  getPerspectiveCamera() {
    this.camera = new PerspectiveCamera(50, this.width / this.height, 0.1, 3000)
    // 摄像机的位置
    this.camera.position.set(150, 300, 300);
    this.camera.lookAt({ x: 0, y: 0, z: 0 })
  }
  // 渲染器
  getrenderder() {
    this.renderers.setSize(this.width, this.height,)
    // 设置canvas的像素比为当前设备的屏幕像素比，避免高分屏下模糊
    this.renderers.setPixelRatio(window.devicePixelRatio);
    this.renderers.shadowMap.enabled = true;
    const pmremGenerator = new THREE.PMREMGenerator(this.renderers);
    this.dom.appendChild(this.renderers.domElement)
    this.scene.environment = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture;
  }
  // 其他选项
  getother() {
    const axes = new AxesHelper(20)
    const grid = new THREE.GridHelper(2000, 20, 0x000000, 0x000000);
    this.scene.add(axes, grid)
  }
  // 动画
  renderScene() {
    const animation = () => {

      this.renderers.render(this.scene, this.camera)

      this.mouseControls.update()

      requestAnimationFrame(animation)

    }

    animation()


  }
  // 点击模型
  onmodelclick = (fun) => {
    this.dom.addEventListener('click', (event) => {
      //获取鼠标坐标
      var mouse = new Vector2();
      var raycaster = new Raycaster();

      let getBoundingClientRect = this.dom.getBoundingClientRect()
      mouse.x = ((event.clientX - getBoundingClientRect!.left) / this.width) * 2 - 1;
      mouse.y = -((event.clientY - getBoundingClientRect!.top) / this.height) * 2 + 1;

      raycaster.setFromCamera(mouse, this.camera); // 通过鼠标点的位置和当前相机的矩阵计算出raycaster
      const intersects = raycaster.intersectObjects(this.scene.children, true);
      fun(intersects[0])
    })

  }
  // 创建轨道控制
  createOrbitControls() {
    this.mouseControls = new OrbitControls(this.camera, this.renderers.domElement)
    this.mouseControls.autoRotate = false; //自转(相机)
    this.mouseControls.autoRotateSpeed = 1; //自转速度
    this.mouseControls.enableDamping = true //滑动阻尼
    this.mouseControls.enablePan = true; //鼠标右键功能
  }
  // 导入glb模型  异步
  async getGlb(url: string) {
    const dracoLoader = new DRACOLoader();
    dracoLoader.setDecoderPath('./gltf/');
    const loader = new GLTFLoader()
    loader.setDRACOLoader(dracoLoader);
    const gltfLoader = new GLTFLoader();
    gltfLoader.setDRACOLoader(dracoLoader);
    const gltf = await gltfLoader.loadAsync(url, (e) => {
      show((e.loaded / 4133072 * 100).toFixed(2) + '%')
      if ((e.loaded / 4133072 * 100) >= 99) {
        hide()
      }
    });
    console.log(gltf);

    const children = gltf.scene.children[0]
    // 出现影子
    this.deepChild(gltf.scene.children, 'children')

    const mixer = new AnimationMixer(children)
    gltf.scene.castShadow = true
    gltf.scene.receiveShadow = true
    this.scene.add(gltf.scene)
    // 是否有动画
    if (gltf.animations[0]) {
      mixer.clipAction(gltf.animations[0]).setDuration(10).play()
      let i = 0.005
      setInterval(() => {
        mixer.update(i)
      })
    }
    return gltf


  }
  // 导入fbx模型
  async getFbx(url: string) {

    const loader = new FBXLoader();
    const object = await loader.loadAsync(url)
    this.scene.add(object)
    // 是否有动画
    if (object.children[0]) {
      const mixer = new AnimationMixer(object.children[0])
      const action = mixer.clipAction(object.animations[0]);
      action.timeScale = 0.8//24帧每秒变为30帧每秒，要慢放为0.8倍，做动画要做30帧/s的
      action.play();
      const clock = new THREE.Clock();
      setInterval(() => {
        const delta = clock.getDelta();
        mixer.update(delta)
      })
    }
    object.traverse(function (child) {

      if (child.isMesh) {

        child.castShadow = true;

        child.receiveShadow = true;
      }

    });

    return object
  }
  // 创建地面
  getPlaneGeometry() {
    const mesh = new THREE.Mesh(new THREE.PlaneGeometry(2000, 2000), new THREE.MeshPhongMaterial({ color: 0x999999, depthWrite: false }));
    mesh.rotation.x = - Math.PI / 2;
    mesh.receiveShadow = true;
    mesh.castShadow = true;
    this.scene.add(mesh);
  }
  pointsMaterial() {
    const material = new MeshBasicMaterial({ color: 0x008888 });
    // 盒子
    const cubeGeometry = new BoxGeometry(40, 40, 40, 20, 20, 20);
    const cube = new Mesh(cubeGeometry, material);
    cube.position.y = 60;
    // cube.position.x = -60;
    cube.receiveShadow = true;
    cube.castShadow = true;
    // 球
    const ballGeometry = new SphereGeometry(20, 40, 32);
    const ball = new Mesh(ballGeometry.clone(), material);
    ball.position.x = 60;
    // points
    const points = new Points(
      ballGeometry,
      new PointsMaterial({
        size: 0.4,
        color: 0x00ffff,
      })
    );
    points.scale.x = 1.5;
    points.scale.y = 1.5;
    points.scale.z = 1.5;

    points.scale.set(2, 2, 2)
    // this.scene.add(ball);
    this.scene.add(cube);
    // this.scene.add(points);
  }
  deepChild(three: any[], key: string) {
    three.map(val => {
      val.castShadow = true;
      val.receiveShadow = true;
      if (val[key]) {
        this.deepChild(val[key], key)
      }
    })
  }
  getBoxGeometry() {

    const material = new MeshBasicMaterial({ color: 0x008888 });
    // 盒子
    const cubeGeometry = new BoxGeometry(40, 40, 40, 20, 20, 20);
    const cube = new Mesh(cubeGeometry, material);
   
    this.scene.add(cube)
  }
}